package org.lilei;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.Socket;
import java.util.Map;

/**
 * @author lilei
 * @date 2020-04-03
 */
public class ProcessorHandler implements Runnable {
    private Socket socket;
    private Map<String, Object> handlerMap;

    public ProcessorHandler(Map<String, Object> handlerMap, Socket socket) {
        this.handlerMap = handlerMap;
        this.socket = socket;
    }

    @Override
    public void run() {
        try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
             ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream())) {

            // 接受请求
            RpcRequest rpcRequest = (RpcRequest) objectInputStream.readObject();

            // 反射调用并且返回结果
            objectOutputStream.writeObject(invoke(rpcRequest));
            objectOutputStream.flush();


        } catch (IOException | ClassNotFoundException | NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
            e.printStackTrace();
        } finally {
            if (socket != null) {
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private Object invoke(RpcRequest rpcRequest) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        String className = rpcRequest.getClassName();
        Object service = handlerMap.get(className);
        if (service == null) {
            throw new RuntimeException("service not found :" + className);
        }
        Class clazz = Class.forName(className);
        Class<?>[] parametersTypes = new Class<?>[rpcRequest.getParameters().length];
        for (int i = 0; i < parametersTypes.length; i++) {
            parametersTypes[i] = rpcRequest.getParameters()[i].getClass();
        }
        Method method = clazz.getMethod(rpcRequest.getMethodName(), parametersTypes);
        return method.invoke(service, rpcRequest.getParameters());
    }
}
